/**
 * @class   IJabberGlooxListener
 * @brief   Interface for JabberGlooxImpl callbacks (events).
 *
 * @see     JabberGlooxImpl
 ****************************************************************************
 * @version 1.01 $Id: JabberGlooxImpl.h 2839 2010-08-04 21:48:26Z alex $
 * @date    Released Stable on 2010-02-21
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Bundles_Devices_JabberGlooxImpl_H__
 #define __WOSH_Bundles_Devices_JabberGlooxImpl_H__

 #include <core/BundleGenericWorker.h>
 #include <interfaces/devices/JabberGloox.h>
 #include <interfaces/services/CommunicatorService.h>
 #include <gloox.h>
 #include <loghandler.h>
 #include <connectionlistener.h>
 #include <messagehandler.h>
 #include <presencehandler.h>
 #include <subscriptionhandler.h>
 #include <messagehandler.h>
 #include <presencehandler.h>
 #include <subscriptionhandler.h>


namespace gloox {
 class Client;
 class ConnectionTCPClient;
 class ConnectionHTTPProxy;
 class RosterManager;
};
class IJabberGlooxListener;


class JabberGlooxImpl : public wosh::BundleGenericWorker,
						public gloox::ConnectionListener,
						public gloox::LogHandler,
						public gloox::SubscriptionHandler,
						public gloox::MessageHandler,
						public gloox::PresenceHandler
 {
	public:
		enum FAILURE_TYPE {
			FAILURE_NONE			= 0x00, ///< no failure
			FAILURE_CONNECTION		= 0x01, // 
			FAILURE_RETRY_LIMIT		= 0x02 // 
		 };

	public:
		/**
		 * @brief   Default constructor. Init vars.
		 * @param bundle [in] the parent bundle, see BundleGenericWorker interface
		 */
		JabberGlooxImpl( wosh::BundleGeneric& bundle );
		/**
		 * @brief   Destructor. If thread is stll running, it will be stopped.
		 */
		virtual ~JabberGlooxImpl();


	public:
		/**
		 * @brief   Send a message to a contact.
		 * @param user [in] recipent user [example: asd123@gmail.com]
		 * @param message [in] message to be sent
		 * @return  true on success; false if thread is not running.
		 * @note    there are no guarantees about sending results
		 */
		virtual bool sendMessage( const std::string& user, const std::string& message ) = 0;
		/**
		 * @brief   Set the presence.
		 * @param available [in] when true the bot will be set as online; else it will appear offline
		 * @return  true on success; false if thread is not running.
		 */
		virtual bool setPresence( bool available, bool force = false ) = 0;


	public:
		virtual WRESULT subscribe( const std::string& account_name, const std::string& opt_message = "" );
		virtual WRESULT unSubscribe( const std::string& account_name, const std::string& opt_message = "" );

/** @name Getters
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief   Get server address
		 * @return  address as string
		 */
		inline const std::string& getServerAddress() const		{ return this->xmppServerAddress; }
		/**
		 * @brief   Get server port
		 * @return  server port
		 */
		inline int getServerPort() const						{ return this->xmppServerPort; }
		/**
		 * @brief   Get Proxy address
		 * @return  address as string (IP:PORT)
		 */
		inline const std::string& getServerProxy() const		{ return this->xmppServerProxy; }

		/**
		 * @brief   Get account username
		 * @return  account username
		 */
		inline const std::string& getAccountName() const		{ return this->xmppAccountName; }

		/**
		 * @brief   Get priority
		 * @return  priority
		 */
		inline int getPriority() const							{ return this->xmppPriority; }

		inline const std::string& getStatusMessage() const		{ return this->xmppPresenceStatus; }

		inline bool isConnected() const							{ return isThreadRunning(); }

		inline int getFailureType() const						{ return this->failureType; }
		inline const std::string& getFailureDescription() const	{ return this->failureDescription; }

		inline int getAutoReconnectMode() const					{ return this->autoReconnectMode; }
		inline long getAutoReconnectDelay() const				{ return this->autoReconnectDelay; }
		inline long getAutoReconnectRetries() const				{ return this->autoReconnectRetries; }


		/**
		 * @brief   Get getJabberGlooxListener interface class for callbacks.
		 * @return  pointer to object which implements callback-functions
		 */
		inline IJabberGlooxListener* getJabberGlooxListener()	{ return this->jabbListener; }


		const char* getConnectionErrorAsString( gloox::ConnectionError ce );

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief   Set server address and port.
		 * @param address [in] address of the server (IP:PORT)
		 * @param port [in] port of the server
		 * @param proxy [in] address of the proxy (IP:PORT)
		 * @return false when internal thread is running; true else
		 */
		bool setServer( const std::string& address, int port, const std::string& proxy = "" );
		/**
		 * @brief   Set server address and port. Provided for convenience.
		 * @param address [in] address of the server (IP:PORT)
		 * @return false when internal thread is running; true else
		 */
		bool setServerAddress( const std::string& address );
		/**
		 * @brief   Set server port.
		 * @param port [in] port of the server
		 * @return false when internal thread is running; true else
		 */
		bool setServerPort( int port );
		/**
		 * @brief   Set proxy address. Provided for convenience.
		 * @param address [in] address of the proxy (IP:PORT)
		 * @return false when internal thread is running; true else
		 */
		bool setServerProxy( const std::string& address );

		/**
		 * @brief   Set server account name and password. Provided for convenience.
		 * @param username [in] username used to log on the server
		 * @param password [in] password used to log on the server
		 * @return false when internal thread is running; true else
		 */
		bool setAccount( const std::string& name, const std::string& pwd );
		/**
		 * @brief   Set account username
		 * @param username [in] username used to log on the server
		 * @return false when internal thread is running; true else
		 */
		bool setAccountUserName( const std::string& name );
		/**
		 * @brief   Set account password
		 * @param password [in] password used to log on the server
		 * @return false when internal thread is running; true else
		 */
		bool setAccountPassword( const std::string& pwd );

		/**
		 * @brief   Set priority of the account (login)
		 * @param value [in] true to set auto-presence
		 * @return false when internal thread is running, true else
		 */
		virtual bool setPriority( int value );

		virtual bool setStatusMessage( const std::string& message );

		void setAutoReconnectMode( int value );
		void setAutoReconnectDelay( long value );
		void setAutoReconnectRetries( long value );

		/**
		 * @brief   Set the IJabberGlooxListener interface for callbacks.
		 * @param listener [in] pointer to object which implements callback-functions
		 * @note    Call this method only once, after creation, it's not reetrant!
		 */
		void setJabberGlooxListener( IJabberGlooxListener* listener ) {
			this->jabbListener = listener;
		 }

//@}
/** @name gloox::LogHandler Interface
 * @{
 ******************************************************************************/
	public:
		virtual void handleLog( gloox::LogLevel level, gloox::LogArea area, const std::string& message );
//@}
/** @name gloox::ConnectionListener Interface
 * @{
 ******************************************************************************/
	public:
		virtual void onConnect();
		virtual void onDisconnect( gloox::ConnectionError e );
		virtual bool onTLSConnect( const gloox::CertInfo& info );
//@}
/** @name Thread methods
 * @{
 ******************************************************************************/
	protected:
		virtual bool initializingThread();
		virtual void runThread();
		virtual void exitingThread();

		virtual bool connect();

//@}
	protected:
		std::string xmppServerAddress;				///< address of the server
		int xmppServerPort;							///< port of the server
		std::string xmppServerProxy;				///< address of the connection proxy

		int autoReconnectMode;
		long autoReconnectDelay;
		long autoReconnectRetries;

		int failureType;
		std::string failureDescription;

		std::string xmppAccountName;				///< Account username of the bot, you should create an account for it
		std::string xmppAccountPwd;					///< Account password of the bot, you should create an account for it

		bool xmppAvailable;							///< presence status (shadow var)
		std::string xmppPresenceStatus;				///< status message (shadow var)
		int xmppPriority;							///< account priority (shadow var)

		IJabberGlooxListener* jabbListener;			///< callbacks for stats (such as JabberGlooxBundle*)

		gloox::Client* xmppJclient;					///< the real implementation from libgloox
		gloox::ConnectionTCPClient* xmppConnClient;	///< proxy: connection
		gloox::ConnectionHTTPProxy* xmppConnProxy;	///< proxy: proxy
		gloox::RosterManager* xmppJRM;				///< RosterManager for subscription managerment


}; // class def


/**
 * @class   IJabberGlooxListener
 * @brief   Interface for JabberGlooxImpl callbacks (events).
 *
 * @see     JabberGlooxImpl
 * @see     wosh::devices::JabberGlooxBundle
 ****************************************************************************
 * @version 0.8.499 $Id: JabberGlooxImpl.h 2839 2010-08-04 21:48:26Z alex $
 * @date    Released Stable on 2010-02-21
 * @author  Alessandro Polo
 ****************************************************************************/
class IJabberGlooxListener
 {
/** @name JabberGloox Events
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief   Raised when a new message is sent to bot's account
		 * @param [in] username username who sent the message
		 * @param [in] message message sent by the user
		 * @param source [in] instance of JabberGlooxImpl which raised the callback
		 */
		virtual void jabbbot_Message( const std::string& username, const std::string& message, JabberGlooxImpl* source ) = 0;

		/**
		 * @brief   Raised when a contact change its presence status (as going online/offline) (also raised periodically)
		 * @param username [in] username of the contact who changed online status (such as online<->offline)
		 * @param presence_status [in] new presence status of the user
		 * @param source [in] instance of JabberGlooxImpl which raised the callback
		 */
		virtual void jabbbot_UserStatus( const std::string& username, int presence_status, const std::string& status_message, JabberGlooxImpl* source ) = 0;

		/**
		 * @brief   Raised when subscription of an user is being updated.
		 * @param username [in] target username
		 * @param subscription_status [in] new subscription status
		 * @param source [in] instance of JabberGlooxImpl which raised the callback
		 */
		virtual short jabbbot_SubscriptionChanged( const std::string& username, int subscription_status, JabberGlooxImpl* source ) = 0;

//@}
	public:
		virtual ~IJabberGlooxListener() { }


}; // class def


#endif //__WOSH_Bundles_Devices_JabberGlooxImpl_H__
